/*
 * Created on March 7, 2007
 * 
 * Copyright (c) Patrick Armstrong 2002-2007. All Rights Reserved
 */
package org.dime.mine.bot;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import org.dime.mine.bot.AwareBoard.AwareLocation;
import org.dime.mine.game.Board;
import org.dime.mine.game.actions.Mark;

/**
 * Investigation // TODO Add type summary
 * 
 * @author Owner
 */
public class Investigation
{
    private static MineBot mineBot;

    private final TestBoard subject;
    private final AwareBoard.AwareLocation lead;

    private final List<TestBoard> validOutcomes = new LinkedList<TestBoard>();
    private final List<TestBoard> invalidOutcomes = new LinkedList<TestBoard>();

    /**
     * 
     */
    public Investigation(Board subject, Board.Location lead)
    {
        this.subject = new TestBoard(subject);
        this.lead = this.subject.getAwareLocation(lead.getRow(), lead
                .getColumn());

        initializeMineBot();
        initializeOutcomes();
    }

    public List<TestBoard> getOutcomes()
    {
        List<TestBoard> outcomes = new LinkedList<TestBoard>(validOutcomes);
        outcomes.addAll(invalidOutcomes);
        return Collections.unmodifiableList(outcomes);
    }

    public List<TestBoard> getValidOutcomes()
    {
        return Collections.unmodifiableList(validOutcomes);
    }

    public List<TestBoard> getInvalidOutcomes()
    {
        return Collections.unmodifiableList(invalidOutcomes);
    }

    private void initializeMineBot()
    {
        if (mineBot == null)
        {
            mineBot = new MineBot();
            mineBot.setStrategyEnabled(MineBot.BURNOUT, false);
            mineBot.setStrategyEnabled(MineBot.CONTRADICTION, false);
            mineBot.setStrategyEnabled(MineBot.EXHAUSTION, false);
            mineBot.setStrategyEnabled(MineBot.GUESS, false);
        }
    }

    private void initializeOutcomes()
    {
        List<TestBoard> outcomes = conjecture();

        Iterator<TestBoard> it = outcomes.iterator();
        TestBoard outcome;
        while (it.hasNext())
        {
            outcome = it.next();
            mineBot.setBoard(outcome);
            while (mineBot.next())
            {}

            if (outcome.isValid())
                validOutcomes.add(outcome);
            else
                invalidOutcomes.add(outcome);
        }
    }

    private List<TestBoard> conjecture()
    {
        if (lead.isSatisfied())
            return Collections.emptyList();

        List<TestBoard> outcomes = new LinkedList<TestBoard>();
        int marksNeeded = lead.getValue() - lead.getMarks();
        List<AwareLocation> neighborhood = lead.getNeighborhood();

        Stack<Integer> indexStack = new Stack<Integer>();
        indexStack.add(0);
        Stack<Mark> actStack = new Stack<Mark>();

        int index;
        AwareLocation loc;
        do
        {
            index = indexStack.peek();
            indexStack.set(indexStack.size() - 1, index + 1);
            if (index < neighborhood.size())
            {
                loc = neighborhood.get(index);
                if (Mark.isMarkable(loc))
                {
                    actStack.push(new Mark(loc));
                    actStack.peek().execute();
                    if (marksNeeded > indexStack.size())
                        indexStack.push(index + 1);
                    else
                    {
                        outcomes.add(new TestBoard(subject, actStack));
                        actStack.pop().undo();
                    }
                }
            }
            else
            {
                indexStack.pop();
                if (!actStack.isEmpty())
                    actStack.pop().undo();
            }
        } while (!indexStack.isEmpty());

        return outcomes;

    }
}